#include"kmp.h"
#include<shlobj.h>
#include"fisier.h"
#include"bruta.h"

const char g_szClassName[]="myWindowClass";
HWND dialog_1 = NULL;
HWND hStartBTN,hCloseBTN,kmp_b,ghid;
HWND dialog_2=NULL;
char *cuvant=(char *)GlobalAlloc(GPTR,100);
char msj[100];
class TextWriter
{private : HFONT hfont;
		   COLORREF textColor;
 public : TextWriter() : hfont(NULL), textColor(RGB(255,255,0))
		  {LOGFONT logFont;
           memset(&logFont, 0, sizeof(logFont));
           logFont.lfHeight = 22; // see PS
           logFont.lfWeight = FW_BOLD;
           strcpy(logFont.lfFaceName, "Tahoma");
           hfont = CreateFontIndirect(&logFont);
		  }
		  void WriteText(HDC _hdc, int _Xpos, int _Ypos, char *_szMessage)//scrie textul din fereastra
		  {//seteaza culoarea textului si fontul
		   COLORREF oldTextColor = SetTextColor(_hdc, textColor);
           HFONT oldHFont = (HFONT)SelectObject(_hdc, hfont);
		   SetBkColor(_hdc,RGB(0,0,200));
           TextOut(_hdc, _Xpos, _Ypos, _szMessage, strlen(_szMessage));

		   //reseteaza culoarea textului si fontul
           SetTextColor(_hdc, oldTextColor);
           SelectObject(_hdc, oldHFont);
		  }
}text;

BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);

BOOL CALLBACK citire(HWND hd, UINT Message, WPARAM wParam, LPARAM lParam)//Citire standard
{dialog_2=hd;
 char text[200];
 switch(Message)
	{case WM_INITDIALOG : return TRUE;
						  break;
	 case WM_COMMAND : switch(LOWORD(wParam))
							{case IDC_BUTTON1 : //Ok
												GetDlgItemText(hd,IDC_EDIT1,(LPSTR)text,199);
												textfis=(char*)malloc(strlen(text)+1);
												strcpy(textfis,text);
												EndDialog(hd,1);
												break;
							 case IDC_BUTTON2: //Anuleaza
											   EndDialog(hd,0);
											   break;
							 default : return FALSE;
							}
	
	}
	
}

void kmp(HWND hdlg,char *p, char *a)//p=cuvantul cautat; a=textul in care se cauta;
{int k, i, j, m=strlen(p), n=strlen(a), count=0;
 char aux[7];
 
 initurm(p);

 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" ");//primul pas-afiseaza un spatiu
 
 for(i=0,j=0;i<n;i++,j++)
		{count=0;
		 nrcomparatii++;
		 while(j >= 0 && a[i] != p[j])
				{//afiseaza caractere din cuvantul cautat
				 if(!count)
					{aux[0]=p[j];
					 aux[1]='\r';
					 aux[2]='\0';
				     SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)aux);
				     SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\n\r");//rand nou
				  
					 //afiseaza spatii pentru a continua de sub caracterele anterioare
					 for(k=0;k<=i-j-1;k++)
						 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" \r");
					 
					 //afiseaza valorile corespunzatoare din vectorul de prefixe
					 for(k=0;k<=j;k++)
					 	{itoa(urmator[k],aux,10);
					 	 if(strlen(aux)==1)//daca !=-1
					 		{aux[1]='\r';
					 		 aux[2]='\0';
					 		}
					 	 else//daca =-1
					 		 {aux[2]='\r';
					 		  aux[3]='\0';
					 		 }
					 	 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)aux);
					 	}//end for

					 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\n\r");//rand nou
					 
				 	}//end if(!count)
			     else 
					 nrcomparatii++;

				 count++;					
				 j=urmator[j];
				 if(j>=0)
					{//afiseaza spatii pentru a ajunge pe pozitia corespunzatoare pe noul rand
					 for(k=0;k<=i;k++)
						 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" \r");
					 
					 //afiseaza caracterul corespunzator in urma nepotrivirii
					 aux[0]=p[j];
					 aux[1]='\r';
					 aux[2]='\0';
					 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)aux);
					 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\n\r");//rand nou

					 //afiseaza spatii pentru a continua sub caracterul anterior
					 if(urmator[j]>=0)
						 for(k=0;k<=i;k++)
							 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" \r");
					 else
						 for(k=0;k<=i-1;k++)
							 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" \r");

					 //afiseaza indexul corespunzator din vectorul de prefixe
					 itoa(urmator[j],aux,10);
					 if(strlen(aux)==1)//daca !=-1
						{aux[1]='\r';
						 aux[2]='\0';
						}
					 else//daca =-1
						 {aux[2]='\r';
						  aux[3]='\0';
						 }
					 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)aux);
					 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\n\r");
					}//end if(j>=0)

				}//end while
		 if(count)
			{//afiseaza spatii pentru a ajunge pe pozitia corespunzatoare pe noul rand
		     for(k=0;k<=i-j;k++)
				 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" \r");
		
			 if(j>0)
				 //afiseaza caractere din cuvant
				 for(k=0;k<j+1;k++)
					{aux[0]=p[k];
					 aux[1]='\r';
					 aux[2]='\0';
					 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)aux);
					}//end for

		    }//end if(count)

		 if(j==-1)
			 continue;//in cazul in care nepotrivirea este de la primul caracter
		   
		 if(count>2)
			 if(j==0)
				 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\r");//afiseaza un spatiu
		   
		 if(count!=1)
			{//afiseaza caracterul din cuvant
		     aux[0]=p[j];
			 aux[1]='\r';
		 	 aux[2]='\0';
			 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)aux);
		    }//end if(count!=1)

		 if(j==m-1)//daca s-a ajuns la sfarsitul cuvantului(daca s-a gasit cuvantul)
			{SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"-cuvantul s-a gasit incepand cu pozitia \r");
			 itoa(i-j+1,aux,10);
			 aux[strlen(aux)]='\r';
			 aux[strlen(aux)]='\0';
			 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)aux);//afiseaza pozitia din text de unde incepe cuvantul
			 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\n\r");//rand nou

			 //afiseaza spatii pentru a ajunge pe pozitia corespunzatoare
			 for(k=0;k<=i-j-1;k++)
				 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" \r");

			 //afiseaza vectorul de prefixe
			 for(k=0;k<=j;k++)
				 {itoa(urmator[k],aux,10);
				  if(strlen(aux)==1)//daca !=-1
					  {aux[1]='\r';
					   aux[2]='\0';
					  }
					 else//daca =-1
						 {aux[2]='\r';
						  aux[3]='\0';
						 }
				  SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)aux);
				 }//end for

			 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\n\r");//rand nou

			 //afiseaza spatii pentru a ajunge pe pozitia corespunzatoare
			 for(k=0;k<=i+1;k++)
				 SendDlgItemMessage(hdlg,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" \r");

			 j=-1;//reinitializare pentru a se relua algoritmul

			}//end if(j==m-1)

		}//end for
 
 //afiseaza numarul de comparatii al algoritmilor
 SetDlgItemInt(hdlg,IDC_EDIT1,nrcomparatii,TRUE);
 brutesearch(cuvant,textfis);
 SetDlgItemInt(hdlg,IDC_EDIT3,compbrut,TRUE);
}

BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{HINSTANCE hInstance=0;
 int len, n=0, i, combo;
 char* buf;                       
 static char car[100],nr[4],sir[100]; 
 static int start=0, pas=0, count=0, count2=0;   //start verifica daca a fost apasat un buton 
 											 	//pas numara la ce pas am ajuns pentru butonul pas urm.
	
 switch(Message)
	{case WM_INITDIALOG : //optiuni citire text
	    				   SendDlgItemMessage(hwnd,IDC_COMBO1,CB_ADDSTRING,1,(LPARAM)"STANDARD");
						   SendDlgItemMessage(hwnd,IDC_COMBO1,CB_ADDSTRING,1,(LPARAM)"FISIER");	
						   SendDlgItemMessage(hwnd,IDC_BUTTON4,BM_SETIMAGE,IMAGE_ICON,(LPARAM)LoadIcon(NULL,MAKEINTRESOURCE(IDI_ASTERISK)));
						   return TRUE;
	 case WM_COMMAND : switch(LOWORD(wParam))
							{case IDC_BUTTON4 : //citire text
												textfis=NULL;
												combo=SendDlgItemMessage(hwnd,IDC_COMBO1,CB_GETCURSEL,0,0);//selecteaza optiunea de citire a textului
												if(combo==1)//citire standard
													DialogBox((HINSTANCE)NULL,MAKEINTRESOURCE(IDD_PROPPAGE_SMALL),hwnd,citire);
												if(combo==0)//citire din fisier
													citirefisier();
												break;
							 case IDC_BUTTON3 : //inchide dialogul(fereastra de afisare a algoritmului)
												EndDialog(hwnd,0);
												break;
							 case IDC_BUTTON1 :	//ruleaza(auto run)
												if(start!=1)//conditie oprire
													break;
												start++;
												if(strlen(cuvant)<1)//conditie oprire
													{MessageBox(hwnd,"Introduceti un cuvant pe care il cautati!","", MB_OK | MB_ICONINFORMATION);
													 break;
													}
												n=SendDlgItemMessage(hwnd,IDC_RADIO1,BM_GETCHECK,0,0);//algoritm
												if(n)//daca e selectat algoritmul
													{GetDlgItemText(hwnd,IDC_EDIT2,(LPSTR)cuvant,99);
													 kmp(hwnd,cuvant,textfis);
													}

												n=SendDlgItemMessage(hwnd,IDC_RADIO2,BM_GETCHECK,0,0);//prefix
												if(n)//daca e selectat prefixul
													{len=GetWindowTextLength(GetDlgItem(hwnd,IDC_EDIT2));//lungimea cuvantului cautat
													 if(len>0)//daca e introdus un cuvant
														{//copiaza cuvantul introdus
														 buf=(char*)GlobalAlloc(GPTR,len+1);
														 GetDlgItemText(hwnd,IDC_EDIT2,buf,len+1);
														 
														 //construieste vectorul de prefixe
														 initurm(buf);
														 
														 //converteaza vectorul de prefixe in caractere pentru a putea fi afisat
														 int count;
														 for(count=0;count<len;count++)
															 {itoa(urmator[count],nr,10);
															  strcat(car,nr);
															 }
														 SendDlgItemMessage(hwnd,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)car);
														 strcpy(car,"");//reinitializare pentru a nu afisa de mai multe ori vectorul de prefixe
														}//end if(len>0)

													}//end if(n)
												break;
							 case IDC_BUTTON2 : //pas urm.(pas cu pas)
												if(start>pas+1)//conditie oprire
													break;
												if(strlen(cuvant)<1)//conditie oprire
													{MessageBox(hwnd,"Introduceti un cuvant pe care il cautati!","", MB_OK | MB_ICONINFORMATION);
													 break;
													}
												start++;
												pas++;

												n=SendDlgItemMessage(hwnd,IDC_RADIO1,BM_GETCHECK,0,0);//algoritm
												if(n)//daca e selectat algoritmul
													kmppas(hwnd,cuvant,textfis,pas);

												n=SendDlgItemMessage(hwnd,IDC_RADIO2,BM_GETCHECK,0,0);//prefix
												if(n)//daca e selectat prefixul
													{len=GetWindowTextLength(GetDlgItem(hwnd,IDC_EDIT2));//lungimea cuvantului cautat
													 if(len>0)//daca e introdus un cuvant
														{//apelul functiei de prefixe se face o data cand se apasa start
														 if(count2<len)
															{//converteaza in caracter pentru a putea fi afisat
															 itoa(urmator[count2],nr,10);
															 count2++;
															 nr[strlen(nr)]='\r';
															 if(count2>=1)
																 SendDlgItemMessage (   hwnd, IDC_EDIT4, EM_REPLACESEL, 0, (LPARAM) nr);
					
															}//end if(count2<len)

														}//end if(len>0)

													}//end if(n)
												break;
							 case IDC_BUTTON5 : //start
												nrfin=0;//nr comparatii pentru forta bruta la pas cu pas
												start=1;//a fost apasat start
												pas=0;//pt pas cu pas
												nrcomparatii=0;//nr comparatii kmp
												count2=0;//pt prefix pas cu pas

												//selecteaza si sterge casuta cu nr comparatii la kmp
												SendDlgItemMessage(hwnd,IDC_EDIT1,EM_SETSEL,0,10);
												SendDlgItemMessage(hwnd,IDC_EDIT1,EM_REPLACESEL,0,(LPARAM)"");

												//selecteaza si sterge casuta cu nr comparatii forta bruta
												SendDlgItemMessage(hwnd,IDC_EDIT3,EM_SETSEL,0,10);
												SendDlgItemMessage(hwnd,IDC_EDIT3,EM_REPLACESEL,0,(LPARAM)"");

												//selecteaza si sterge ecranul de afisare
												SendDlgItemMessage(hwnd,IDC_EDIT4,EM_SETSEL,0,10000);
												SendDlgItemMessage(hwnd,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)" ");

												strcpy(cuvant,"");//initializare pentru citire cuvant cautat
												GetDlgItemText(hwnd,IDC_EDIT2,cuvant,99);//citeste cuvantul cautat
												initurm(cuvant);//construieste vectorul de prefixe

												n=SendDlgItemMessage(hwnd,IDC_RADIO1,BM_GETCHECK,0,0); //algoritm
												if(n)//daca e selectat cuvantul
													{//afiseaza textul in care trebuie cautat cuvantul
													 if(textfis!=NULL)//daca este introdus text in care se cauta
														 {//afiseaza textul in care se cauta
														  SendDlgItemMessage(hwnd,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)textfis);

														  SendDlgItemMessage(hwnd,IDC_EDIT4,EM_SETSEL,strlen(textfis)+1,strlen(textfis)+1);//selecteaza ultimul caracter(primul dupa sfarsitul textului) pentru a trece la rand nou
														  SendDlgItemMessage(hwnd,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\r\n");//rand nou
														 }//end if(textfis!=NULL)
				
													}//end if(n)

												n=SendDlgItemMessage(hwnd,IDC_RADIO2,BM_GETCHECK,0,0);//prefix
												if(n)//daca e selectat prefixul
													{//afiseaza cuvantul
													 len=GetWindowTextLength(GetDlgItem(hwnd, IDC_EDIT2));//lungimea cuvantului
													 GetDlgItemText(hwnd,IDC_EDIT2,(LPSTR)cuvant,99);//selecteaza textul
													 cuvant[len]='\0';//terminator de sif(pentru a putea muta caracterele la dreapta cu o pozitie)

													 //muta la dreapta caracterele cuvantului cu o pozitie
													 for(i=strlen(cuvant);i>0;i--)
														 cuvant[i]=cuvant[i-1];
													 cuvant[0]=' ';//pune spatiu la inceput(primul element din vectorul de prefixe este -1, necesar(spatiul) pentru a se afisa exact sub caracter -1)
													 
													 SetDlgItemText(hwnd,IDC_EDIT4,cuvant);//afiseaza cuvantul
													 SendDlgItemMessage(hwnd,IDC_EDIT4,EM_SETSEL,strlen(cuvant),strlen(cuvant));//selecteaza ultimul caracter(primul dupa sfarsitul cuvantului) pentru a trece la rand nou
													 SendDlgItemMessage(hwnd,IDC_EDIT4,EM_REPLACESEL,0,(LPARAM)"\r\n");//rand nou

													}//end if(n)
				
												break;
							}//end switch(LOWORD(wParam))
			
	 default : return FALSE;
	}//end switch(Message)
 return TRUE;
}

int i=0;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)//fereastra de inceput
{i++;
 switch(msg)
	{case WM_COMMAND : switch(LOWORD(wParam))
							{case BN_CLICKED : //daca se apasa un buton
											   if(hCloseBTN==(HWND)lParam)//daca e exit
												   DestroyWindow(hwnd);//inchidere
											   if(hStartBTN==(HWND)lParam)//daca e start aplicatie
												   dialog_1=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDHELP),hwnd,AboutDlgProc);//deschide dialogul(fereastra algoritmului)
											   if(ghid==(HWND)lParam)
												   ShellExecute(hwnd,"open","Manual de instalare si utilizare.pdf",0,0,SW_SHOWNORMAL);
											   if(kmp_b==(HWND)lParam)
						   				    	   ShellExecute(NULL,"open","http://code.google.com/p/metode-de-cautare-in-siruri-kmp/wiki/kmp",NULL,NULL,SW_SHOWNORMAL);
								 }
							 break;
	 case WM_CREATE :
					  hStartBTN=CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "START APLICATIE",
								WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 50, 150, 40, hwnd, NULL,
								GetModuleHandle(NULL), NULL);//construieste butonul start aplicatie
					  hCloseBTN=CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "EXIT",
								WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 200, 150, 40, hwnd, NULL,
								GetModuleHandle(NULL), NULL);//construieste butonul exit
					  kmp_b=CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "KMP",
								WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 150, 150, 40, hwnd, NULL,
								GetModuleHandle(NULL), NULL);//construieste butonul kmp
					  ghid=CreateWindowEx(WS_EX_WINDOWEDGE, "BUTTON", "MOD DE UTILIZARE",
								WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 100, 150, 40, hwnd, NULL,
								GetModuleHandle(NULL), NULL);//construieste butonul mod de utilizare
		break;
	 case WM_PAINT:{//construieste interfata(vizuala) de inceput a aplicatiei
					HRGN hrgn;
					HBRUSH hbr;
					PAINTSTRUCT lppaint;
					HDC hdc=BeginPaint(hwnd,&lppaint);
					hrgn=CreateEllipticRgn(200,50,550,150);
					hbr=CreateSolidBrush(RGB(0,0,200));
					FillRgn(hdc,hrgn,hbr);
					text.WriteText(hdc,210,90,"ALGORITMUL KNUTH MORISS PRATT");
					SetBkMode(hdc,0);
					TextOut(hdc,400,170,"versiunea 1.00",14);
					TextOut(hdc,240,250,"PROIECT REALIZAT DE:",20);
					TextOut(hdc,270,270,"Std. Talas Andrei Florin",24);
					TextOut(hdc,270,290,"Std. Malutan Sergiu Beniamin",28);
					EndPaint(hwnd,&lppaint);
					  break;
				   }
     case WM_CLOSE : DestroyWindow(hwnd);
					 break;
	 case WM_DESTROY : PostQuitMessage(0);
					   break;
	 default : return DefWindowProc(hwnd,msg,wParam,lParam);

	}//end switch(msg)

 return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)//construieste fereastra de inceput
{WNDCLASSEX wc;
 HWND hwnd;
 MSG Msg;
 wc.cbSize        = sizeof(WNDCLASSEX);
 wc.style         = 0;
 wc.lpfnWndProc   = WndProc;
 wc.cbClsExtra    = 0;
 wc.cbWndExtra    = 0;
 wc.hInstance     = hInstance;
 wc.hIcon         = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));
 wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0xff,0xff,200));
 wc.lpszMenuName  = NULL;
 wc.lpszClassName = g_szClassName;
 wc.hIconSm       = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));

 if(!RegisterClassEx(&wc))
    {MessageBox(NULL,"Window Registration Failed!","Error!",MB_ICONEXCLAMATION | MB_OK);
     return 0;
    }

 hwnd=CreateWindowEx(WS_EX_CLIENTEDGE,g_szClassName,"KNUTH MORRIS PRATT",WS_OVERLAPPEDWINDOW,400,150,600,400,NULL,NULL,hInstance,NULL);//construieste fereastra
 
 if(hwnd == NULL)
	 {MessageBox(NULL, "Window Creation Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);
      return 0;
	 }
 ShowWindow(hwnd, nCmdShow);
 UpdateWindow(hwnd);

 while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {TranslateMessage(&Msg);
     DispatchMessage(&Msg);
    }
    return Msg.wParam;
}